#include "MpgDecoder.hpp"
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>

MpgDecoder::MpgDecoder() {
    mad_stream_init(&stream);
    mad_stream_options(&stream, MAD_OPTION_IGNORECRC);
    mad_frame_init(&frame);
    mad_header_init(&header);
    mad_synth_init(&synth);
    //duration=mad_timer_zero;
}
MpgDecoder::~MpgDecoder() {
    close();
}

bool MpgDecoder::load(const char* filename, bool silence) {
    struct stat st;
    stat(filename, &st);
    size = st.st_size;
    FILE *f=fopen(filename, "rb");
    char *tmp=(char*)malloc(sizeof(char)*size);
    buffer=(unsigned char*)malloc(sizeof(unsigned char)*size);
    fgets(tmp, size, f);
    memcpy(tmp, buffer, size);
    free(tmp);
    fclose(f);
    channels=synth.pcm.channels;
    std::cout<<"Channels: "<<channels<<std::endl;
    frequency=synth.pcm.samplerate;
    std::cout<<"SR: "<<frequency<<std::endl;
    samples=(unsigned long long)synth.pcm.samples;
    mad_stream_buffer(&stream, buffer, size);
    /*float *tmpf=(float*)malloc(sizeof(float)*16);
    decode(tmpf, 16);*/
    seekable=true;
    return true;
}

void MpgDecoder::close() {
    mad_synth_finish(&synth);
    mad_frame_finish(&frame);
    mad_stream_finish(&stream);
    free(buffer);
}

int MpgDecoder::decode(float* data, unsigned long frames) {
    unsigned int i;
    while (mad_frame_decode(&frame, &stream)!=-1) {
        mad_header_decode(&header, &stream); //?
        mad_synth_frame(&synth, &frame);
        // output PCM conversion from 24bits integer to 32bits float
        i=0;
        for(unsigned short s=0; s<1152; s++) {
            for(unsigned short c=0; c<synth.pcm.channels; c++) {
                data[i]=(2*synth.pcm.samples[c][s]+MAD_RANGE)/(2*MAD_MAX_24_BITS_VALUE);
                i++;
                if(i>=frames) return i;
            }
        }
    }
    return i;
}

bool MpgDecoder::seek(unsigned int time) {
    //position=mpg123_seek_frame(mh, time, SEEK_SET); //todo
    return position>=0;
}
